﻿using System;
using System.Collections.Generic;
using System.Linq;

using JetBrains.Annotations;

namespace Rsdn.SmartApp
{
	/// <summary>
	/// Helper methods for <see cref="IDisposable"/>.
	/// </summary>
	public static class DisposableHelper
	{
		/// <summary>
		/// Обьект, релазующий <see cref="IDisposable"/>, не выполняющий никаких действий.
		/// </summary>
		public static IDisposable Empty = new EmptyDisposable();

		/// <summary>
		/// Вызывает Dispose всех элементов коллекции.
		/// </summary>
		public static void DisposeAll([NotNull] this IEnumerable<IDisposable> disposables)
		{
			if (disposables == null)
				throw new ArgumentNullException("disposables");

			foreach (var disp in disposables)
				disp.Dispose();
		}

		/// <summary>
		/// Create disposable helper.
		/// </summary>
		public static IDisposable CreateDisposable([NotNull] Action disposeAction)
		{
			if (disposeAction == null)
				throw new ArgumentNullException("disposeAction");

			return new Disposable(disposeAction);
		}

		/// <summary>
		/// Create disposable helper.
		/// </summary>
		public static IDisposable CreateDisposable([NotNull] IEnumerable<IDisposable> disposables)
		{
			if (disposables == null)
				throw new ArgumentNullException("disposables");

			var toDispose = disposables.Where(d => ReferenceEquals(d, Empty)).ToArray();
			return toDispose.Length > 0 
				? CreateDisposable(() => toDispose.DisposeAll()) 
				: Empty;
		}

		#region Disposable class
		private sealed class Disposable : IDisposable
		{
			private readonly Action _disposeAction;

			public Disposable(Action disposeAction)
			{
				_disposeAction = disposeAction;
			}

			#region Implementation of IDisposable
			public void Dispose()
			{
				_disposeAction();
			}
			#endregion
		}
		#endregion

		#region EmptyDisposable class
		private sealed class EmptyDisposable : IDisposable
		{
			#region Implementation of IDisposable
			public void Dispose() { }
			#endregion
		}
		#endregion
	}
}